﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using System.Windows.Forms;
using System.Drawing;
using System.Threading;
using System.ComponentModel;

namespace VisionEstereo
{
	// Clase privada para representar los argumentos del algoritmo
	class ArgsImagenes
	{
		private Bitmap bitmapIzquierda;
		private Bitmap bitmapDerecha;
		// Los parámetros
		private Object parametros;
		
		public ArgsImagenes(Bitmap bitmapIzquierda, Bitmap bitmapDerecha, Object parametros)
		{
			this.bitmapIzquierda = bitmapIzquierda;
			this.bitmapDerecha = bitmapDerecha;
			this.parametros = parametros;
		}
		
		// Propiedades
		public Bitmap BitmapIzquierda
		{
			get
			{
				return bitmapIzquierda;
			}
			set
			{
				this.bitmapIzquierda = value;
			}
		}
		
		public Bitmap BitmapDerecha
		{
			get
			{
				return bitmapDerecha;
			}
			set
			{
				this.bitmapDerecha = value;
			}
		}
		
		public Object Parametros
		{
			get
			{
				return parametros;
			}
			set
			{
				this.parametros = value;
			}
		}
	}
	
    public partial class SeleccionImagenes
    {
		// Atributos (imágenes)
		private Bitmap bitmapIzquierda;
		private Bitmap bitmapDerecha;
        private Bitmap bitMapInicial;
		private Bitmap resultadoAlgoritmoDisparidades;
		private Bitmap resultadoAlgoritmo;
		private int disparidadMaxima;
		private int disparidadMedia;
		
		// Atributos (tipo de algoritmo)
		private App.TipoAlgoritmo tipoAlgoritmo;
		
		// Atributos (parámetros del algoritmo)
		private Object parametrosAlgoritmo;
		
		// Atributos (hilos)
		private BackgroundWorker worker;
		private Progreso pd;

        //Atributos Esquema Correlacion
        private Boolean es_esquemaCorrelacion;
        private VisionEstereo.AlgoritmoCorrelacion.EsquemaCorrelacion esquemaCorrelacion;
		
        public SeleccionImagenes()
        {
            this.InitializeComponent();

            // Insert code required on object creation below this point.
        }
        public void setEsquemaAlg(VisionEstereo.AlgoritmoCorrelacion.EsquemaCorrelacion esquemaCorrelacion)
        {
            es_esquemaCorrelacion = true;
            this.esquemaCorrelacion = esquemaCorrelacion;
        }  

		public SeleccionImagenes(App.TipoAlgoritmo tipoAlgoritmo, Object parametrosAlgoritmo)
		{
			this.InitializeComponent();
			this.tipoAlgoritmo = tipoAlgoritmo;
			this.parametrosAlgoritmo = parametrosAlgoritmo;
		}

        private void cargarImagenIzquierda_Click(object sender, System.Windows.RoutedEventArgs e)
        {
            // Abrimos un cuadro de diálogo
            OpenFileDialog dialogoAbrir = new OpenFileDialog();
            dialogoAbrir.Filter = "Archivos de imagen|*.jpg;*.png;*.bmp";
            dialogoAbrir.Title = "Seleccione la imagen izquierda";
			
            if (dialogoAbrir.ShowDialog() == DialogResult.OK)
            {
				bitmapIzquierda = new Bitmap(dialogoAbrir.FileName);
				this.imagenIzquierda.Fill = new ImageBrush(new BitmapImage(new Uri(dialogoAbrir.FileName)));
                bitMapInicial = new Bitmap(dialogoAbrir.FileName);
            }
        }

        private void cargarImagenDerecha_Click(object sender, System.Windows.RoutedEventArgs e)
        {
        	// Abrimos un cuadro de diálogo
            OpenFileDialog dialogoAbrir = new OpenFileDialog();
            dialogoAbrir.Filter = "Archivos de imagen|*.jpg;*.png;*.bmp";
            dialogoAbrir.Title = "Seleccione la imagen derecha";
			
            if (dialogoAbrir.ShowDialog() == DialogResult.OK)
            {
				bitmapDerecha = new Bitmap(dialogoAbrir.FileName);
				this.imagenDerecha.Fill = new ImageBrush(new BitmapImage(new Uri(dialogoAbrir.FileName)));
            }
        }

        private void botonSiguiente_Click(object sender, System.Windows.RoutedEventArgs e)
        {
        	// Validamos que el usuario haya cargado las dos imágenes
			if (this.imagenDerecha.Fill.Equals(System.Windows.Media.Brushes.White)  || this.imagenIzquierda.Fill.Equals(System.Windows.Media.Brushes.White))
			{
				MensajeError error = new MensajeError();
				error.WindowStartupLocation = WindowStartupLocation.CenterScreen;
				error.setMensajeError("Debe seleccionar dos imágenes antes de continuar.");
				error.ShowDialog();
			}
			else
			{		
		     	// Llamamos al algoritmo   
				pd = new Progreso();     
				pd.Cancel += CancelProcess;     
				
				System.Windows.Threading.Dispatcher pdDispatcher = pd.Dispatcher;     
				// Creamos el hilo en segundo plano    
				worker = new BackgroundWorker();    
				worker.WorkerSupportsCancellation = true;     
				worker.DoWork += delegate(object s, DoWorkEventArgs args)
				{
					ArgsImagenes parametro = (ArgsImagenes)args.Argument;
					if (tipoAlgoritmo.Equals(App.TipoAlgoritmo.AlgoritmoEstandar))
					{
						args.Result = ProyectoSI.ProyectoSI.AlgoritmoEstandar(parametro.BitmapIzquierda, parametro.BitmapDerecha, (ProyectoSI.ParametrosAlgoritmoEstandar)parametro.Parametros);
					}
					else if (tipoAlgoritmo.Equals(App.TipoAlgoritmo.AlgoritmoLankton))
					{
						args.Result = ProyectoSI.ProyectoSI.AlgoritmoLankton(parametro.BitmapIzquierda, parametro.BitmapDerecha, (ProyectoSI.ParametrosAlgoritmoLankton)parametro.Parametros);
					}
					else if (tipoAlgoritmo.Equals(App.TipoAlgoritmo.AlgoritmoLankton2))
					{
						args.Result = ProyectoSI.ProyectoSI.AlgoritmoLankton2(parametro.BitmapIzquierda, parametro.BitmapDerecha, (ProyectoSI.ParametrosAlgoritmoLankton)parametro.Parametros);
					}
					else if (tipoAlgoritmo.Equals(App.TipoAlgoritmo.DeteccionObjetos))
					{
						args.Result = ProyectoSI.ProyectoSI.DeteccionBitmapObjetos(parametro.BitmapIzquierda, parametro.BitmapDerecha, (ProyectoSI.ParametrosObtencionObjetos)parametro.Parametros);
					}
					else
					{
						// El usuario quiere visualizar el anaglifo
						args.Result = ProyectoSI.ProyectoSI.MostrarAnaglifo(parametro.BitmapIzquierda, parametro.BitmapDerecha);
					}
				};     
				worker.RunWorkerCompleted += delegate(object s, RunWorkerCompletedEventArgs args)    
				{
					// El algoritmo de detección de objetos devuelve un contenedor
					if (!tipoAlgoritmo.Equals(App.TipoAlgoritmo.DeteccionObjetos))
					{
						resultadoAlgoritmoDisparidades = (Bitmap)args.Result;
					}
					else
					{
						resultadoAlgoritmoDisparidades = ((ProyectoSI.ContenedorBitmapDisparidad)args.Result).BitmapContenedor;
						disparidadMaxima = ((ProyectoSI.ContenedorBitmapDisparidad)args.Result).DisparidadMaxima;
						disparidadMedia = ((ProyectoSI.ContenedorBitmapDisparidad)args.Result).DisparidadMedia;

					}
					pd.Close();
					
					System.Windows.Media.Imaging.BitmapSource bitmapSourceMostrar = null;
					System.Windows.Media.Imaging.BitmapSource bitmapSourceDisparidades = null;
					
					
					// Aplicamos una función que extrae el mapa de colores a partir
					// de las disparidades
					// TODO: Dar la opción al usuario para ver la imagen en B/N también
					if (!tipoAlgoritmo.Equals(App.TipoAlgoritmo.Anaglifo))
					{
						if (tipoAlgoritmo.Equals(App.TipoAlgoritmo.AlgoritmoEstandar))
						{
							resultadoAlgoritmo = ProyectoSI.ColorMapDisparidades.ObtenerColorMap(resultadoAlgoritmoDisparidades, ((ProyectoSI.ParametrosAlgoritmoEstandar)parametrosAlgoritmo).RangoPixeles);
						}
						else if (tipoAlgoritmo.Equals(App.TipoAlgoritmo.DeteccionObjetos))
						{
							// El resultado es directamente lo que retorna el algoritmo
							resultadoAlgoritmo = resultadoAlgoritmoDisparidades;
						}
						else
						{
							resultadoAlgoritmo = ProyectoSI.ColorMapDisparidades.ObtenerColorMap(resultadoAlgoritmoDisparidades, ((ProyectoSI.ParametrosAlgoritmoLankton)parametrosAlgoritmo).MaximaDisparidad);
						}
						// Convertimos a BitmapSource
						bitmapSourceMostrar = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(resultadoAlgoritmo.GetHbitmap(), IntPtr.Zero, Int32Rect.Empty, System.Windows.Media.Imaging.BitmapSizeOptions.FromEmptyOptions());
					}
					
					// Convertimos a BitmapSource
					bitmapSourceDisparidades = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(resultadoAlgoritmoDisparidades.GetHbitmap(), IntPtr.Zero, Int32Rect.Empty, System.Windows.Media.Imaging.BitmapSizeOptions.FromEmptyOptions());
					
					// Creamos una nueva página, le pasamos el resultado y navegamos hacia ella
                   
                    ResultadosAlgoritmo paginaResult = new ResultadosAlgoritmo();
                    
					
					if (!tipoAlgoritmo.Equals(App.TipoAlgoritmo.Anaglifo))
					{
						paginaResult.setImagenResultado(bitmapSourceMostrar);
                        paginaResult.setDisparidad(((ProyectoSI.ParametrosAlgoritmoLankton)this.parametrosAlgoritmo).MaximaDisparidad);
					}
					else
					{
						paginaResult.setImagenResultado(bitmapSourceDisparidades);
                        paginaResult.fueraFiltro();
                        paginaResult.fueraLabel();
					}
					// Guardamos la matriz de disparidades
					paginaResult.setImagenDisparidades(resultadoAlgoritmoDisparidades);
                    paginaResult.setImagenInicial(bitmapIzquierda);
                    if (tipoAlgoritmo.Equals(App.TipoAlgoritmo.Anaglifo))
                    {
                        paginaResult.setImagenInicial(bitMapInicial);
                    }
					// Para la parte de detección de objetos, guardamos la disparidad
					// máxima y media
					if (tipoAlgoritmo.Equals(App.TipoAlgoritmo.DeteccionObjetos))
					{
						paginaResult.setDisparidadesMaximaYMedia(disparidadMaxima, disparidadMedia);
					}
					
					// Ponemos el tipo de algoritmo para que para ciertos algoritmos
					// no se pueda mostrar disparidades al hacer clic (no disponen de mapa de disparidades)
					paginaResult.setTipoAlgoritmo(tipoAlgoritmo);
					
					// Guardamos la leyenda de ColorMap
					// Navegamos hacia la página
                    paginaResult.setTamañoImagenReal(bitmapDerecha.Size.Width, bitmapDerecha.Size.Height);

                     if(es_esquemaCorrelacion){
                        /*Se trata del Esquema del Algoritmo de Correlación*/
                         esquemaCorrelacion.setMapaDisparidades(resultadoAlgoritmoDisparidades,resultadoAlgoritmo);
                         
                        esquemaCorrelacion.setImagenDisparidad(bitmapSourceMostrar);                        
                        this.NavigationService.Navigate(esquemaCorrelacion);
                    }
                    else{
					    this.NavigationService.Navigate(paginaResult);
                     }
				};     
				// Ejecutamos el proceso y mostramos la barra de progreso
				ArgsImagenes argumento = new ArgsImagenes(bitmapIzquierda, bitmapDerecha, parametrosAlgoritmo);
				worker.RunWorkerAsync(argumento);    
			}
		}
			
		public delegate void UpdateProgressDelegate(int percentage, int recordCount); 
			
		//this is the method that the deleagte will execute
		public void UpdateProgressText(int percentage, int recordCount)
		{    //set our progress dialog text and value    
			pd.TextoProgreso = "Espere, por favor...";
		} 
		
		void CancelProcess(object sender, EventArgs e)
		{   
			// Cancelamos el proceso    
			worker.CancelAsync();
		}
	}
}